///////////////////////////////////////////////////////////////////////////////
///// Assignment 3: CPU Scheduler
///// By: Brady Robichaud (robicb82) & Patrick Filtz (filtzp43)
///// Date: 4/19/2013
///// File: Queue.java
///// Description: This class deals with the formating and printing of the
/////	queues and information, adding processes to the queues, incrementing
/////	the wait time for the queues, and setting if the process is ready.	
///////////////////////////////////////////////////////////////////////////////
package round2;

import java.util.HashMap;

public abstract class Queue {
	int idleTime;
	Node cpuRoot;
	Node cpuHead;
	Node cpuTail;
	
	Node ioRoot;
	Node ioHead;
	Node ioTail;
	
	Process[] ps;
	HashMap<Integer, Process> psHash = new HashMap<Integer, Process>();
	
	String cpuOutput = "";
	String ioOutput = "";
	String title;
	
	//Formats and prints queue and calculated information to GUI and terminal
	protected String getSummary(){
		String finalOut = "";
		
		//Start cpu Queue
		Node curNode = cpuRoot;
		String cpuOut = "";
		
		while(curNode != null){
			if(!curNode.waitNode || (curNode.nextNode != null && curNode.waitTime > 0)){
				cpuOut += curNode.print();
			}
			curNode = curNode.nextNode;
		}
		
		finalOut+=(title);
		finalOut+=("\n-- CPU Queue --\n");
		cpuOut += "|";
		
		for(int i = 0; i < cpuOut.length(); i++){
			finalOut+=("-");
		}
		finalOut+=("\n" + cpuOut + "\n");
		for(int i = 0; i < cpuOut.length(); i++){
			finalOut+=("-");
		}
		finalOut+="\n";
		// end cpuQueue
		
		//start io Queue
		finalOut+=("-- IO Queue --\n");
		curNode = ioRoot;
		String ioOut = "";
		for(int i = 0; curNode != null; i++){
			if(!curNode.waitNode || curNode.waitTime > 0){
				ioOut += curNode.print();
			}
			curNode = curNode.nextNode;
		}
		if(ioOut.length() > 0){
			ioOut += "|";
		}else{
			ioOut = "Empty Queue.";
		}
		for(int i = 0; i < ioOut.length(); i++){
			finalOut+=("-");
		}
		
		finalOut+=("\n" + ioOut + "\n");
		
		for(int i = 0; i < ioOut.length(); i++){
			finalOut+=("-");
		}
		finalOut+=("\n\n");
		// end IO Queue
		
		//Summary
		finalOut+=("Idle time = " + idleTime + "\n");
		
		int numProcs = ps.length;
		int[] waits = new int[numProcs];
		int[] turnArounds = new int[numProcs];
		double avgWait = 0.0;
		double avgTurnAround = 0.0;
		
		Process p;
		//calculate avgWait and average turn around time
		for(int i = 0; i < numProcs; i++){
			p = ps[i];
			finalOut+=("P" + p.pID + " wait time = " + (waits[i] = p.waitingTime) + "\n");
			avgWait += (double)waits[i];
			finalOut+=("P" + p.pID + " turn around time = " + (turnArounds[i] = p.turnAroundTime) + "\n");
			avgTurnAround += (double)turnArounds[i];
		}
		
		finalOut+=("Average wait time = " + avgWait/numProcs + "\n");
		finalOut+=("Average turn around time = " + avgTurnAround/numProcs + "\n");
		return finalOut;
	}
	
	//Adds IO process to the queue
	protected void addIO(Process p){
		Node newN = new Node(p.pID, p.bursts[p.curIndex], p.bursts[p.curIndex], true);
		if(ioHead.waitNode){
			ioHead.nextNode = newN;
			ioHead = ioHead.nextNode;
		}else{
			Node curNode = ioHead;
			while(!curNode.nextNode.waitNode){
				curNode = curNode.nextNode;
			}
			curNode.nextNode = newN;
		}
	}
	
	//Increments the wait time if the current node is wait node
	protected void incrementWaits(Node head){
		if(head.waitNode){
			head.waitTime++;
		}else{
			Node curNode = head.nextNode;
			while(curNode != null && !curNode.waitNode){
				if(!curNode.isIO){
					curNode.waitTime++;
					psHash.get(curNode.pID).waitingTime++;
				}
				curNode = curNode.nextNode;
			}
		}
	}
	
	//Checks to see if there are any active nodes in the queue
	//Used in checking for termination
	protected boolean anyActive(){	
		for(int i = 0; i < ps.length; i++){
			if(ps[i].hasMore()){
				return true;
			}
		}
		return false;
	}
	
	//Checks to see if the process is ready
	protected void setProcReady(int pid, boolean ready){
		psHash.get(pid).burstReady = ready;
	}
}
